/* * This is a common dao with basic CRUD operations and is not limited to any * persistent layer implementation * * Copyright (C) 2008 Imran M Yousuf (imyousuf@smartitengineering.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package com.smartitengineering.dao.impl.hibernate; import com.smartitengineering.dao.common.queryparam.BasicCompoundQueryParameter; import com.smartitengineering.dao.common.queryparam.BiOperandQueryParameter; import com.smartitengineering.dao.common.queryparam.CompositionQueryParameter; import com.smartitengineering.dao.common.queryparam.OperatorType; import com.smartitengineering.dao.common.queryparam.QueryParameter; import com.smartitengineering.dao.common.queryparam.QueryParameterCastHelper; import com.smartitengineering.dao.common.queryparam.QueryParameterWithOperator; import com.smartitengineering.dao.common.queryparam.QueryParameterWithPropertyName; import com.smartitengineering.dao.common.queryparam.QueryParameterWithValue; import com.smartitengineering.dao.common.queryparam.SimpleNameValueQueryParameter; import com.smartitengineering.dao.common.queryparam.ValueOnlyQueryParameter; import com.smartitengineering.domain.PersistentDTO; import java.io.Serializable; import java.util.Collection; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import org.hibernate.Criteria; import org.hibernate.FetchMode; import org.hibernate.Session; import org.hibernate.criterion.AggregateProjection; import org.hibernate.criterion.Conjunction; import org.hibernate.criterion.CountProjection; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Disjunction; import org.hibernate.criterion.Expression; import org.hibernate.criterion.Junction; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Order; import org.hibernate.criterion.Projection; import org.hibernate.criterion.ProjectionList; import org.hibernate.criterion.Projections; import org.hibernate.criterion.PropertyProjection; import org.hibernate.criterion.Restrictions; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; public abstract class AbstractDAO<Template extends PersistentDTO> extends HibernateDaoSupport implements Serializable { private Map<Criteria, ProjectionList> projections = new WeakHashMap<Criteria, ProjectionList>(); protected void createEntity(Template... entities) { if (entities == null) { throw new IllegalArgumentException(); } Session session; boolean customSession = false; try { session = getSessionFactory().getCurrentSession(); } catch (Exception ex) { session = getSessionFactory().openSession(); customSession = true; } try { for (Template entity : entities) { session.save(entity); } } finally { if (session != null) { session.flush(); if (customSession && session.isOpen()) { session.close(); } } } } protected void updateEntity(Template... entities) { if (entities == null) { throw new IllegalArgumentException(); } Session session; boolean customSession = false; try { session = getSessionFactory().getCurrentSession(); } catch (Exception ex) { session = getSessionFactory().openSession(); customSession = true; } try { for (Template entity : entities) { session.update(entity); } } finally { if (session != null) { session.flush(); if (customSession && session.isOpen()) { session.close(); } } } } protected void deleteEntity(Template... entities) { if (entities == null) { throw new IllegalArgumentException(); } Session session; boolean customSession = false; try { session = getSessionFactory().getCurrentSession(); } catch (Exception ex) { session = getSessionFactory().openSession(); customSession = true; } try { for (Template entity : entities) { session.delete(entity); } } finally { if (session != null) { session.flush(); if (customSession && session.isOpen()) { session.close(); } } } } protected Template readSingle(Class entityClass, Hashtable<String, QueryParameter> parameter) { return readSingle(entityClass, parameter.values().toArray( new QueryParameter[0])); } protected Object readOther(Class entityClass, Hashtable<String, QueryParameter> parameter) { return readOther(entityClass, parameter.values().toArray( new QueryParameter[0])); } protected List<? extends Object> readOtherList(Class entityClass, Hashtable<String, QueryParameter> parameter) { return readOtherList(entityClass, parameter.values().toArray( new QueryParameter[0])); } protected List<Template> readList(Class entityClass, Hashtable<String, QueryParameter> parameter) { return readList(entityClass, parameter.values().toArray( new QueryParameter[0])); } protected Template readSingle(Class entityClass, List<QueryParameter> parameter) { return readSingle(entityClass, parameter.toArray(new QueryParameter[0])); } protected <OtherTemplate extends Object> OtherTemplate readOther( Class entityClass, List<QueryParameter> parameter) { return this.<OtherTemplate>readOther(entityClass, parameter.toArray(new QueryParameter[0])); } protected <OtherTemplate extends Object> List<OtherTemplate> readOtherList( Class entityClass, List<QueryParameter> parameter) { return readOtherList(entityClass, parameter.toArray( new QueryParameter[0])); } protected List<Template> readList(Class entityClass, List<QueryParameter> parameter) { return readList(entityClass, parameter.toArray(new QueryParameter[0])); } protected Template readSingle(Class entityClass, QueryParameter... parameter) { Session session; boolean customSession = false; try { session = getSessionFactory().getCurrentSession(); } catch (Exception ex) { session = getSessionFactory().openSession(); customSession = true; } try { Criteria criteria = simpleSearchCriteria(session, entityClass, parameter); return (Template) criteria.uniqueResult(); } catch (Exception e) { throw new IllegalArgumentException(e); } finally { if (session != null) { if (customSession && session.isOpen()) { session.close(); } } } } protected <OtherTemplate extends Object> OtherTemplate readOther( Class entityClass, QueryParameter... parameter) { Session session; boolean customSession = false; try { session = getSessionFactory().getCurrentSession(); } catch (Exception ex) { session = getSessionFactory().openSession(); customSession = true; } try { Criteria criteria = simpleSearchCriteria(session, entityClass, parameter); return (OtherTemplate) criteria.uniqueResult(); } catch (Exception e) { throw new IllegalArgumentException(e); } finally { if (session != null) { if (customSession && session.isOpen()) { session.close(); } } } } protected <OtherTemplate extends Object> List<OtherTemplate> readOtherList( Class entityClass, QueryParameter... parameter) { Session session; boolean customSession = false; try { session = getSessionFactory().getCurrentSession(); } catch (Exception ex) { session = getSessionFactory().openSession(); customSession = true; } try { Criteria criteria = simpleSearchCriteria(session, entityClass, parameter); return criteria.list(); } catch (Exception e) { throw new IllegalArgumentException(e); } finally { if (session != null) { if (customSession && session.isOpen()) { session.close(); } } } } protected List<Template> readList(Class entityClass, QueryParameter... parameter) { Session session; boolean customSession = false; try { session = getSessionFactory().getCurrentSession(); } catch (Exception ex) { session = getSessionFactory().openSession(); customSession = true; } try { Criteria criteria = simpleSearchCriteria(session, entityClass, parameter); return criteria.list(); } catch (Exception e) { throw new IllegalArgumentException(e); } finally { if (session != null) { if (customSession && session.isOpen()) { session.close(); } } } } protected Criteria simpleSearchCriteria(Session session, Class queryClass, QueryParameter... parameter) { Criteria criteria = session.createCriteria(queryClass); for (QueryParameter param : parameter) { if (!param.isInitialized()) { continue; } String propertyName = getPropertyName(param); processCriteria(criteria, propertyName, param); } return criteria; } @SuppressWarnings("unchecked") private void processCriteria(Criteria criteria, String element, QueryParameter parameter) { switch (parameter.getParameterType()) { case PARAMETER_TYPE_PROPERTY: { criteria.add(getCriterion(element, parameter)); return; } case PARAMETER_TYPE_ORDER_BY: { final Order order; SimpleNameValueQueryParameter<com.smartitengineering.dao.common.queryparam.Order> queryParameter = QueryParameterCastHelper.SIMPLE_PARAM_HELPER.cast(parameter); com.smartitengineering.dao.common.queryparam.Order requestedOrder = queryParameter.getValue(); switch (requestedOrder) { case ASC: { order = Order.asc(element); break; } case DESC: { order = Order.desc(element); break; } default: { order = null; break; } } if (order != null) { criteria.addOrder(order); } return; } case PARAMETER_TYPE_MAX_RESULT: { ValueOnlyQueryParameter<Integer> queryParameter = QueryParameterCastHelper.VALUE_PARAM_HELPER.cast(parameter); criteria.setMaxResults(queryParameter.getValue()); return; } case PARAMETER_TYPE_FIRST_RESULT: { ValueOnlyQueryParameter<Integer> queryParameter = QueryParameterCastHelper.VALUE_PARAM_HELPER.cast(parameter); criteria.setFirstResult(queryParameter.getValue()); return; } case PARAMETER_TYPE_DISJUNCTION: { processDisjunction(criteria, parameter); return; } case PARAMETER_TYPE_CONJUNCTION: { processConjunction(criteria, parameter); return; } case PARAMETER_TYPE_NESTED_PROPERTY: { processNestedParameter(criteria, element, parameter); return; } case PARAMETER_TYPE_COUNT: { final Projection countProjection = Projections.count(element); setProjection(criteria, countProjection); return; } case PARAMETER_TYPE_ROW_COUNT: { final Projection rowCount = Projections.rowCount(); setProjection(criteria, rowCount); return; } case PARAMETER_TYPE_SUM: { final AggregateProjection sum = Projections.sum(element); setProjection(criteria, sum); return; } case PARAMETER_TYPE_MAX: { final AggregateProjection max = Projections.max(element); setProjection(criteria, max); return; } case PARAMETER_TYPE_MIN: { final AggregateProjection min = Projections.min(element); setProjection(criteria, min); return; } case PARAMETER_TYPE_AVG: { final AggregateProjection avg = Projections.avg(element); setProjection(criteria, avg); return; } case PARAMETER_TYPE_GROUP_BY: { final PropertyProjection groupProperty = Projections.groupProperty(element); setProjection(criteria, groupProperty); return; } case PARAMETER_TYPE_COUNT_DISTINCT: { final CountProjection countDistinct = Projections.countDistinct(element); setProjection(criteria, countDistinct); return; } case PARAMETER_TYPE_DISTINCT_PROP: { final Projection distinct = Projections.distinct(Projections.property(element)); setProjection(criteria, distinct); return; } case PARAMETER_TYPE_UNIT_PROP: { final PropertyProjection property = Projections.property(element); setProjection(criteria, property); return; } } } @SuppressWarnings("unchecked") private void processNestedParameter(Criteria criteria, String element, QueryParameter parameter) { FetchMode mode; CompositionQueryParameter queryParameter = QueryParameterCastHelper.COMPOSITION_PARAM_FOR_NESTED_TYPE.cast( parameter); switch (queryParameter.getFetchMode()) { case EAGER: mode = FetchMode.EAGER; break; case SELECT: mode = FetchMode.SELECT; break; case JOIN: mode = FetchMode.JOIN; break; case LAZY: mode = FetchMode.LAZY; break; default: case DEFAULT: mode = FetchMode.DEFAULT; break; } criteria.setFetchMode(element, ((mode == null) ? FetchMode.JOIN : mode)); Collection<QueryParameter> nestedParameters = queryParameter. getNestedParameters(); if (nestedParameters == null || nestedParameters.size() <= 0) { return; } Criteria nestedCriteria = criteria.createCriteria(element); for (QueryParameter nestedQueryParameter : nestedParameters) { if (!nestedQueryParameter.isInitialized()) { continue; } processCriteria(nestedCriteria, getPropertyName(nestedQueryParameter), nestedQueryParameter); } } @SuppressWarnings("unchecked") private void processCriterion(Junction criterion, String element, QueryParameter parameter) { switch (parameter.getParameterType()) { case PARAMETER_TYPE_PROPERTY: { criterion.add(getCriterion(element, parameter)); return; } case PARAMETER_TYPE_CONJUNCTION: { processConjunction(criterion, parameter); break; } case PARAMETER_TYPE_DISJUNCTION: { processDisjunction(criterion, parameter); break; } } } @SuppressWarnings("unchecked") private void processDisjunction(Criteria criteria, QueryParameter parameter) { Disjunction disjunction = Expression.disjunction(); workOnNestedParams(parameter, disjunction); criteria.add(disjunction); } @SuppressWarnings("unchecked") private void processConjunction(Criteria criteria, QueryParameter parameter) { Conjunction conjunction = Expression.conjunction(); workOnNestedParams(parameter, conjunction); criteria.add(conjunction); } @SuppressWarnings("unchecked") private void processDisjunction(Junction junction, QueryParameter parameter) { Disjunction disjunction = Expression.disjunction(); workOnNestedParams(parameter, disjunction); junction.add(disjunction); } @SuppressWarnings("unchecked") private void processConjunction(Junction junction, QueryParameter parameter) { Conjunction conjunction = Expression.conjunction(); workOnNestedParams(parameter, conjunction); junction.add(conjunction); } private Criterion getCriterion(String element, QueryParameter queryParamemter) { OperatorType operator = getOperator(queryParamemter); Object parameter = getValue(queryParamemter); switch (operator) { case OPERATOR_EQUAL: { return Expression.eq(element, parameter); } case OPERATOR_LESSER: { return Expression.lt(element, parameter); } case OPERATOR_LESSER_EQUAL: { return Expression.le(element, parameter); } case OPERATOR_GREATER: { return Expression.gt(element, parameter); } case OPERATOR_GREATER_EQUAL: { return Expression.ge(element, parameter); } case OPERATOR_NOT_EQUAL: { return Expression.ne(element, parameter); } case OPERATOR_IS_NULL: { return Expression.isNull(element); } case OPERATOR_IS_NOT_NULL: { return Expression.isNotNull(element); } case OPERATOR_IS_EMPTY: { return Expression.isEmpty(element); } case OPERATOR_IS_NOT_EMPTY: { return Expression.isNotEmpty(element); } case OPERATOR_STRING_LIKE: { MatchMode hibernateMatchMode; com.smartitengineering.dao.common.queryparam.MatchMode matchMode = getMatchMode(queryParamemter); if (matchMode == null) { matchMode = com.smartitengineering.dao.common.queryparam.MatchMode.EXACT; } switch (matchMode) { case END: hibernateMatchMode = MatchMode.END; break; case EXACT: hibernateMatchMode = MatchMode.EXACT; break; case START: hibernateMatchMode = MatchMode.START; break; default: case ANYWHERE: hibernateMatchMode = MatchMode.ANYWHERE; break; } return Expression.like(element, parameter.toString(), hibernateMatchMode); } case OPERATOR_BETWEEN: { parameter = getFirstParameter(queryParamemter); Object parameter2 = getSecondParameter(queryParamemter); return Expression.between(element, parameter, parameter2); } case OPERATOR_IS_IN: { Collection inCollectin = QueryParameterCastHelper.MULTI_OPERAND_PARAM_HELPER.cast( queryParamemter).getValues(); return Restrictions.in(element, inCollectin); } case OPERATOR_IS_NOT_IN: { Collection inCollectin = QueryParameterCastHelper.MULTI_OPERAND_PARAM_HELPER.cast( queryParamemter).getValues(); return Restrictions.not(Restrictions.in(element, inCollectin)); } } return null; } private String getPropertyName( QueryParameter param) { final String propertyName; if (param instanceof QueryParameterWithPropertyName) { propertyName = ((QueryParameterWithPropertyName) param).getPropertyName(); } else { propertyName = ""; } return propertyName; } private void setProjection(Criteria criteria, final Projection projection) { ProjectionList currentProjections = projections.get( criteria); if (currentProjections == null) { currentProjections = Projections.projectionList(); projections.put(criteria, currentProjections); criteria.setProjection(currentProjections); } currentProjections.add(projection); } private void workOnNestedParams(QueryParameter parameter, Junction criterion) { BasicCompoundQueryParameter queryParameter = QueryParameterCastHelper.BASIC_COMPOUND_PARAM_HELPER.cast(parameter); Collection<QueryParameter> nestedParameters = queryParameter.getNestedParameters(); for (QueryParameter nestedParam : nestedParameters) { if (!nestedParam.isInitialized()) { continue; } processCriterion(criterion, getPropertyName(nestedParam), nestedParam); } } private OperatorType getOperator(QueryParameter queryParamemter) { if (QueryParameterCastHelper.BASIC_COMPOUND_PARAM_HELPER.isWithOperator( queryParamemter)) { QueryParameterWithOperator parameterWithOperator = QueryParameterCastHelper.BI_OPERAND_PARAM_HELPER. castToOperatorParam( queryParamemter); return parameterWithOperator.getOperatorType(); } else { return null; } } private Object getValue(QueryParameter queryParamemter) { Object value; if (queryParamemter instanceof QueryParameterWithValue) { value = ((QueryParameterWithValue) queryParamemter).getValue(); } else { value = null; } if (value == null) { value = ""; } return value; } private Object getSecondParameter(QueryParameter queryParamemter) { if (queryParamemter instanceof BiOperandQueryParameter) { return QueryParameterCastHelper.BI_OPERAND_PARAM_HELPER.cast( queryParamemter).getSecondValue(); } else { return ""; } } private Object getFirstParameter(QueryParameter queryParamemter) { if (queryParamemter instanceof BiOperandQueryParameter) { return QueryParameterCastHelper.BI_OPERAND_PARAM_HELPER.cast( queryParamemter).getFirstValue(); } else { return ""; } } private com.smartitengineering.dao.common.queryparam.MatchMode getMatchMode( QueryParameter queryParamemter) { return QueryParameterCastHelper.STRING_PARAM_HELPER.cast(queryParamemter). getMatchMode(); } }